package com.brainhealth.customer.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.brainhealth.common.constant.CacheConstants;
import com.brainhealth.common.core.redis.RedisCache;
import com.brainhealth.common.enums.CustomerExerciseStatus;
import com.brainhealth.common.enums.PayBusinessType;
import com.brainhealth.common.enums.PayStatus;
import com.brainhealth.common.utils.DateCalcUtils;
import com.brainhealth.common.utils.DateUtils;
import com.brainhealth.common.utils.SnowFlakeUtil;
import com.brainhealth.common.utils.StringUtils;
import com.brainhealth.customer.domain.*;
import com.brainhealth.customer.domain.vo.ExerciseOrderPayVO;
import com.brainhealth.customer.mapper.*;
import com.brainhealth.customer.service.ICustomerService;
import com.brainhealth.customer.service.IExerciseOrderService;
import com.brainhealth.utils.AdapayUtils;
import com.brainhealth.utils.CommonUtils;
import com.brainhealth.utils.FillBeanUtils;
import com.huifu.adapay.core.AdapayCore;
import com.huifu.adapay.core.util.AdapaySign;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

/**
 * 会员训练订单Service业务层处理
 * 
 * @author wolong
 * @date 2023-05-09
 */
@Service
public class ExerciseOrderServiceImpl implements IExerciseOrderService
{
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ExerciseOrderMapper exerciseOrderMapper;
    @Autowired
    private ExerciseProductMapper exerciseProductMapper;
    @Autowired
    private CustomerExerciseMapper customerExerciseMapper;
    @Autowired
    private ExerciseOrderPayMapper exerciseOrderPayMapper;
    @Autowired
    private RedisCache redisCache;
    @Resource
    RedissonClient redissonClient;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private ChatMainMapper chatMainMapper;

    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 查询会员训练订单
     *
     * @param exerciseOrderId 会员训练订单主键
     * @return 会员训练订单
     */
    @Override
    public ExerciseOrder selectExerciseOrderByExerciseOrderId(Long exerciseOrderId)
    {
        return exerciseOrderMapper.selectExerciseOrderByExerciseOrderId(exerciseOrderId);
    }

    @Override
    public ExerciseOrder selectExerciseOrderByOrderId(String orderId)
    {
        return exerciseOrderMapper.selectExerciseOrderByOrderId(orderId);
    }

    @Override
    public List<ExerciseOrder> getCustomerOrderList(HttpServletRequest request)
    {
        Customer customer = CommonUtils.getCustomerByRequest(request);
        ExerciseOrder query = new ExerciseOrder();
        query.setCustomerId(customer.getCustomerId());
        return selectExerciseOrderList(query);
    }

    /**
     * 查询会员训练订单列表
     *
     * @param exerciseOrder 会员训练订单
     * @return 会员训练订单
     */
    @Override
    public List<ExerciseOrder> selectExerciseOrderList(ExerciseOrder exerciseOrder)
    {
        return exerciseOrderMapper.selectExerciseOrderList(exerciseOrder);
    }

    @Override
    public ExerciseOrder getCustomerExerciseOrder(Customer customer,ExerciseOrder exerciseOrder) {
        exerciseOrder.setCustomerId(customer.getCustomerId());
        List<ExerciseOrder> exerciseOrderList = exerciseOrderMapper.selectExerciseOrderList(exerciseOrder);
        if (CollectionUtils.isEmpty(exerciseOrderList)) {
            logger.warn("未查询到该用户的订单记录，用户ID：{}，昵称：{}", customer.getCustomerId(), customer.getNickName());
            return null;
        }
        if (exerciseOrderList.size() > 1) {
            logger.warn("用户有两个及以上的训练中的训练，用户ID：{}，昵称：{}", customer.getCustomerId(), customer.getNickName());
        }
        ExerciseOrder order = exerciseOrderList.get(0);
        return order;
    }

    @Override
    public ExerciseOrder getExerciseOrder(Customer customer) {
        ExerciseOrder exerciseOrderParam=new ExerciseOrder();
        exerciseOrderParam.setStatus(PayStatus.Exercise);
        ExerciseOrder exerciseOrder = getCustomerExerciseOrder(customer,exerciseOrderParam);
        if (null == exerciseOrder) {
            exerciseOrderParam.setStatus(PayStatus.Finish);
            exerciseOrder = getCustomerExerciseOrder(customer, exerciseOrderParam);
        }
        return exerciseOrder;
    }

    @Override
    public String getOrderNo(Customer customer) {
        ExerciseOrder exerciseOrderParam = new ExerciseOrder();
        exerciseOrderParam.setStatus(PayStatus.Exercise);
        ExerciseOrder exerciseOrder = getCustomerExerciseOrder(customer, exerciseOrderParam);

        exerciseOrderParam.setStatus(PayStatus.Finish);
        ExerciseOrder finishExerciseOrder = getCustomerExerciseOrder(customer, exerciseOrderParam);

        return null!=exerciseOrder? exerciseOrder.getOrderId():finishExerciseOrder.getOrderId();
    }

    @Override
    public ExerciseOrder createExerciseOrder(HttpServletRequest request, ExerciseOrderPayVO exerciseOrderPayVO)
    {
        Customer customer = CommonUtils.getCustomerByRequest(request);
        ExerciseProduct query = new ExerciseProduct();
        query.setExerciseProductId(exerciseOrderPayVO.getExerciseProductId());
        ExerciseProduct exerciseProduct = exerciseProductMapper.selectExerciseProductByExerciseProductId(exerciseOrderPayVO.getExerciseProductId());
        ExerciseOrder exerciseOrder = new ExerciseOrder();
        exerciseOrder.setPayAmount(exerciseProduct.getPrice());
        exerciseOrder.setAmount(exerciseProduct.getPrice());
        exerciseOrder.setCustomerId(customer.getCustomerId());
        exerciseOrder.setCustomerName(customer.getNickName());
        exerciseOrder.setCustomerPhone(customer.getPhone());
        exerciseOrder.setCycle(exerciseProduct.getCycle());
        exerciseOrder.setExerciseDesc(exerciseProduct.getDescription());
        exerciseOrder.setExerciseName(exerciseProduct.getName());
        exerciseOrder.setExerciseProductId(exerciseProduct.getExerciseProductId());
        exerciseOrder.setCreateTime(new Date());
        exerciseOrder.setPayType(exerciseOrderPayVO.getPayType());
        exerciseOrder.setStatus(PayStatus.Unpaid);
        exerciseOrder.setOrderId(SnowFlakeUtil.getDefaultSnowFlakeId().toString());
        int result = exerciseOrderMapper.insertExerciseOrder(exerciseOrder);
        if (result > 0)
        {
            try
            {
                redisCache.setCacheObject(CacheConstants.ORDER_TIME + customer.getPhone(), DateCalcUtils.addMinute(exerciseOrder.getCreateTime(), 30), 30, TimeUnit.MINUTES);
                RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque("async-hand-msg");
                RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
                delayedQueue.offer(exerciseOrder.getOrderId(), 30L, TimeUnit.MINUTES);
                String s = TimeUnit.SECONDS.toSeconds(30) + "分钟";
                logger.info("添加延时队列成功 ，延迟时间：" + s);
                return exerciseOrder;
            } catch (Exception e)
            {
                logger.error(e.getMessage());
            }
            logger.info("------消息已添加---------");
        }
        return exerciseOrder;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ExerciseOrder customerExerciseOrderPay(HttpServletRequest request, ExerciseOrderPayVO exerciseOrderPayVO)
    {
        ExerciseOrder exerciseOrder = exerciseOrderMapper.selectExerciseOrderByOrderId(exerciseOrderPayVO.getOrderId());
        if (exerciseOrder.getStatus() != PayStatus.Unpaid)
        {
            return null;
        }
        if (exerciseOrder.getStatus() == PayStatus.Unpaid && !StringUtils.isNullOrEmpty(exerciseOrder.getPayUrl()))
        {
            return exerciseOrder;
        }
        try
        {
            AdapayUtils.initAdapay();
            //todo 测试支付订单金额写死 0.01   必须是带小数的数据
            //exerciseOrder.setPayAmount(new BigDecimal(0.01));
            Map<String, Object> paymentResult = AdapayUtils.executePayment(exerciseOrderPayVO.getOrderId(), exerciseOrderPayVO.getPayType(), exerciseOrder.getPayAmount(), exerciseOrderPayVO.getOpenId(), PayBusinessType.BUY_PRODUCT);
            ExerciseOrderPay exerciseOrderPay = new ExerciseOrderPay();
            exerciseOrderPay.setOrderId(exerciseOrder.getOrderId());
            exerciseOrderPay.setAdapayRequest(JSON.toJSONString(exerciseOrderPayVO));
            exerciseOrderPay.setAdapayResponse(JSON.toJSONString(paymentResult));
            exerciseOrderPay.setCreateTime(new Date());
            exerciseOrderPayMapper.insertExerciseOrderPay(exerciseOrderPay);
            if (paymentResult.get("status").equals("succeeded"))
            {
                JSONObject obj = JSONObject.parseObject(paymentResult.get("expend").toString());
                String resUrl = obj.get("pay_info").toString();
                exerciseOrder.setPayType(exerciseOrderPayVO.getPayType());
                DecimalFormat df1 = new DecimalFormat("0.00");
                exerciseOrder.setPayAmount(new BigDecimal(df1.format(exerciseOrder.getPayAmount())));
                exerciseOrder.setPayUrl(resUrl);
                exerciseOrder.setUpdateTime(new Date());
                exerciseOrderMapper.updateExerciseOrder(exerciseOrder);
                return exerciseOrder;
            }
            return null;
        } catch (Exception e)
        {
            //todo 支付出现异常把订单处理为异常订单
            logger.error("支付接口调用失败！{}" , e.getMessage());
            return null;
        }
    }

    @Override
    public Date exerciseOrderRemainTime(HttpServletRequest request)
    {
        Customer customer = CommonUtils.getCustomerByRequest(request);
        Date orderTime = redisCache.getCacheObject(CacheConstants.ORDER_TIME + customer.getPhone());
        if (orderTime == null)
        {
            return null;
        }
        return orderTime;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean customerExerciseOrderSuccess(String orderId, String adapayId)
    {
        if (lock.tryLock())
        {
            try
            {
                ExerciseOrder order = exerciseOrderMapper.selectExerciseOrderByOrderId(orderId);
                logger.info("支付前开始获取订单信息" + JSON.toJSON(order));
                if (order.getStatus() == PayStatus.Unpaid)
                {
                    order.setStatus(PayStatus.Paid);
                    order.setTransactionNo(adapayId);
                    order.setPayTime(new Date());
                    updateExerciseOrder(order);
                    ChatMain queryChatMain = new ChatMain();
                    queryChatMain.setCustomerId(order.getCustomerId());
                    List<ChatMain> lstChatMain = chatMainMapper.selectChatMainList(queryChatMain);
                    if (lstChatMain.size() > 0)
                    {
                        ChatMain chatMain = lstChatMain.get(0);
                        chatMain.setNextOrderNo(order.getOrderId());
                        chatMainMapper.updateChatMain(chatMain);
                    }
                    logger.info("修改订单支付状态" + JSON.toJSON(order));
                    ExerciseProduct exerciseProduct = exerciseProductMapper.selectExerciseProductByExerciseProductId(order.getExerciseProductId());
                    List<CustomerExercise> lstCustomerExercise = FillBeanUtils.fillCustomerExerciseList(exerciseProduct, order);
                    int result = customerExerciseMapper.batchInsertCustomerExercise(lstCustomerExercise);
                    if (result > 0)
                    {
                        logger.info("修改当前支付的订单为训练状态");
                        //如果会员当前没有训练中的订单则把当前已支付的订单状态修改为训练中
                        ExerciseOrder queryExercise = new ExerciseOrder();
                        queryExercise.setCustomerId(order.getCustomerId());
                        List<ExerciseOrder> lstExerciseOrder = exerciseOrderMapper.selectExerciseOrderList(queryExercise);
                        ExerciseOrder exerciseOrder = lstExerciseOrder.stream().filter(item -> item.getStatus() == PayStatus.Exercise).findFirst().orElse(null);
                        Customer customer = customerService.selectCustomerByCustomerId(order.getCustomerId());
                        //如果是普通用户则直接切换订单
                        if (exerciseOrder == null && customer.getMechanismId() == null)
                        {
                            logger.info("重置当前正在训练中的订单" + customer.getCustomerId());
                            payOrderReset(customer, lstExerciseOrder, lstCustomerExercise);
                        }
                        //如果是体验会员没有完成订单去支付
                        if (exerciseOrder != null && customer.getMechanismId().equals(-1L))
                        {
                            logger.info("1、重置体验会员正在训练中的订单" + customer.getCustomerId());
                            exerciseOrder.setStatus(PayStatus.Finish);
                            updateExerciseOrder(exerciseOrder);
                            payOrderReset(customer, lstExerciseOrder, lstCustomerExercise);
                            customerService.initNomalCustomer(customer.getCustomerId());
                            Customer ExperienceCustomer = customerService.selectCustomerByCustomerId(customer.getCustomerId());
                            customerService.updateCustomerInfo(ExperienceCustomer);
                        }
                        //如果是体验会员完成了订单去支付
                        if (exerciseOrder == null && customer.getMechanismId().equals(-1L))
                        {
                            logger.info("2、重置体验会员正在训练中的订单" + customer.getCustomerId());
                            payOrderReset(customer, lstExerciseOrder, lstCustomerExercise);
                            customerService.initNomalCustomer(customer.getCustomerId());
                            Customer ExperienceCustomer = customerService.selectCustomerByCustomerId(customer.getCustomerId());
                            customerService.updateCustomerInfo(ExperienceCustomer);
                        }
                        return true;
                    }
                }
            } catch (Exception e)
            {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                logger.error("订单支付回调异常！", e);
                return false;
            } finally
            {
                lock.unlock();
            }
        }
        return false;
    }

    //当前支付的订单的状态切换
    public void payOrderReset(Customer customer, List<ExerciseOrder> lstExerciseOrder, List<CustomerExercise> lstCustomerExercise)
    {
        ExerciseOrder paidOrder = lstExerciseOrder.stream().filter(item -> item.getStatus() == PayStatus.Paid).findFirst().orElse(null);
        if (paidOrder != null)
        {
            paidOrder.setStatus(PayStatus.Exercise);
            paidOrder.setPayTime(new Date());
            updateExerciseOrder(paidOrder);
            List<CustomerExercise> lstNext = lstCustomerExercise.stream().filter(item -> item.getCountSort() == 1).collect(Collectors.toList());
            for (CustomerExercise nextExercise : lstNext)
            {
                nextExercise.setStatus(CustomerExerciseStatus.NoFinish);
                nextExercise.setOpenTime(new Date());
            }
            customer.setCountSort(1l);
            logger.info("把体验会员变成普通会员");
            customerService.updateCustomerInfo(customer);
        }
    }

    @Override
    public void customerExerciseOrderCallback(HttpServletRequest request, HttpServletResponse response)
    {
        try
        {
            //验签请参data
            String data = request.getParameter("data");
            //验签请参sign
            String sign = request.getParameter("sign");
            //验签标记
            boolean checkSign;
            //验签请参publicKey
            String publicKey = AdapayCore.PUBLIC_KEY;
            logger.info("验签请参：data={}sign={}");
            //验签
            checkSign = AdapaySign.verifySign(data, sign, publicKey);
            //验签成功逻辑
            JSONObject adapayObject = JSONObject.parseObject(data);
            if (checkSign)
            {
                //验签成功逻辑
                String orderId = adapayObject.get("order_no").toString();
                if (adapayObject.get("status").equals("succeeded"))
                {
                    String adapayId = adapayObject.get("id").toString();
                    customerExerciseOrderSuccess(orderId, adapayId);
                } else
                {
                    //订单回调支付失败，修改订单状态为失败
                    ExerciseOrder order = exerciseOrderMapper.selectExerciseOrderByOrderId(orderId);
                    order.setStatus(PayStatus.Failed);
                    order.setUpdateTime(new Date());
                    exerciseOrderMapper.updateExerciseOrder(order);
                }
                logger.info("成功返回数据data:" + data);
            } else
            {
                //验签失败逻辑
                logger.error("异步回调验签失败！" + data);
            }
            ExerciseOrderPay orderPay = new ExerciseOrderPay();
            orderPay.setCreateTime(new Date());
            orderPay.setAdapayRequest("汇付返回支付回调");
            orderPay.setOrderId(adapayObject.get("order_no").toString());
            orderPay.setAdapayResponse(data);
            response.setStatus(200);
            exerciseOrderPayMapper.insertExerciseOrderPay(orderPay);
        } catch (Exception e)
        {
            logger.info("异步回调开始，参数，request={}");
        }
    }

    /**
     * 新增会员训练订单
     *
     * @param exerciseOrder 会员训练订单
     * @return 结果
     */
    @Override
    public int insertExerciseOrder(ExerciseOrder exerciseOrder)
    {
        exerciseOrder.setCreateTime(DateUtils.getNowDate());
        return exerciseOrderMapper.insertExerciseOrder(exerciseOrder);
    }

    /**
     * 修改会员训练订单
     *
     * @param exerciseOrder 会员训练订单
     * @return 结果
     */
    @Override
    public int updateExerciseOrder(ExerciseOrder exerciseOrder)
    {
        exerciseOrder.setUpdateTime(DateUtils.getNowDate());
        return exerciseOrderMapper.updateExerciseOrder(exerciseOrder);
    }

    /**
     * 批量删除会员训练订单
     *
     * @param exerciseOrderIds 需要删除的会员训练订单主键
     * @return 结果
     */
    @Override
    public int deleteExerciseOrderByExerciseOrderIds(Long[] exerciseOrderIds)
    {
        return exerciseOrderMapper.deleteExerciseOrderByExerciseOrderIds(exerciseOrderIds);
    }

    /**
     * 删除会员训练订单信息
     *
     * @param exerciseOrderId 会员训练订单主键
     * @return 结果
     */
    @Override
    public int deleteExerciseOrderByExerciseOrderId(Long exerciseOrderId)
    {
        return exerciseOrderMapper.deleteExerciseOrderByExerciseOrderId(exerciseOrderId);
    }
}
